import java.math.BigDecimal;
import java.util.Arrays;

/**
 * @author lichenxi
 * @date 2020/3/31
 */
public class Vector {

    //向量值数组
    public Double[] values;

    //零向量
    public static Vector zeroVector(int len){
        Double[] doubles = new Double[len];
        for (int i = 0; i < doubles.length; i++) {
            doubles[i] = 0.0;
        }
        return new Vector(doubles);
    }

    //处理精度
    public Vector proAcc(int acc,int type){
        for (int i = 0; i < this.getlen(); i++) {
                BigDecimal bigDecimal = new BigDecimal(this.values[i]);
                this.values[i] = bigDecimal.setScale(acc,type).doubleValue();
        }
        return this ;
    }

    //向量和矩阵的乘法
    public Vector mulMatrix(Matrix matrix){
        return matrix.mulVector(this);
    }

    //求两向量的夹角
    public Double angleVector(Vector vector) throws ArithmeticException{
        if (!(this.getlen()).equals(vector.getlen())){
            throw new RuntimeException("向量维度不相同");
        }else{
            Double aDouble = this.pointMul(vector);
            try {
                //大于零为锐角
                //小于零为钝角
                double v = aDouble / (this.scakarVerctor() * vector.scakarVerctor());
                //弧度
                double acos = Math.acos(v);
                //角度=弧度/2/PI*360
                double angle = acos/2/Math.PI*360;
                return angle;
            }catch (ArithmeticException e){
                throw e;
            }

        }
    }

    //向量积要考虑坐标系

    //向量的点乘 相似度
    public Double pointMul(Vector vector) throws RuntimeException{
        if (!(this.getlen()).equals(vector.getlen())){
            throw new RuntimeException("点乘的向量维度不相同");
        }else{
            Double sum = 0.0;
            for (int i = 0; i < this.values.length; i++) {
                sum+=this.values[i]*vector.getItem(i);
            }
            return sum;
        }
    }

    //向量的单位向量(长度为1)(每个分量除以模)
    public Vector unitVector() throws RuntimeException{
        if (this.scakarVerctor().equals(0.0)){
            throw new RuntimeException("模长为0");
        }
        Double[] doubles = new Double[this.getlen()];
        for (int i = 0; i < doubles.length; i++) {
            doubles[i] = (this.values[i])/this.scakarVerctor();
        }
        return new Vector(doubles);
    }

    //向量的模
    public Double scakarVerctor(){
        Double scakarValue = new Double(0.0);
        for (int i = 0; i < values.length; i++) {
            scakarValue+=Math.pow(values[i],2);
        }
        //开方必须是1.0来除
        return Math.pow(scakarValue,1.0/2);
    }

    //向量的反向
    public Vector revVector(){
        Double[] doubles = Arrays.copyOf(this.values, this.values.length);
        for (int i = 0; i < doubles.length; i++) {
            doubles[i] *= -1;
        }
        return new Vector(doubles);
    }

    //向量的数字除法
    public Vector divNumber(Double number){
       return this.mulNumber(1/number);
    }

    //向量的数字乘法
    public Vector mulNumber(Double number){
        Double[] doubles = Arrays.copyOf(this.values, this.values.length);
        for (int i = 0; i < doubles.length; i++) {
            doubles[i] = doubles[i]*number;
        }
        return new Vector(doubles);
    }

    //向量的减法
    public Vector subVector(Vector vector) throws RuntimeException{
        //判断长度相同才有意义
       return this.addVector(vector.revVector());
    }

    //向量的加法
    public Vector addVector(Vector vector) throws RuntimeException{
        //判断长度相同才有意义
        if (!(this.getlen()).equals(vector.getlen())){
            throw new RuntimeException("相加的向量维度不相同");
        }else{
            Double[] doubles = new Double[this.getlen()];
            for (int a = 0;a<this.getlen();a++){
                doubles[a] = this.getItem(a)+vector.getItem(a);
            }
            return new Vector(doubles);
        }
    }

    //向量的维度
    public Integer getlen(){
        return this.values.length;
    }

    //获取向量的第index元素
    public Double getItem(int index){
        return this.values[index];
    }

    //构造
    Vector(Double[] doubles){
        this.values = Arrays.copyOf(doubles, doubles.length);
    }

    @Override
    public String toString() {
        String val = "";
        for (int i = 0;i<this.getlen();i++){
            val+=this.values[i];
            if (i<this.getlen()-1){
                val+=",";
            }
        }
        return "Vector{" +
                "values=[" + val +
                "]}";
    }
}
